package com.sunricher.telinkblemeshlib;

import android.nfc.Tag;
import android.nfc.tech.NfcA;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import com.sunricher.telinkblemeshlib.callback.NfcToolCallback;
import com.sunricher.telinkblemeshlib.util.HexUtil;

import java.util.Arrays;
import java.util.List;

public class NfcToolManager {

    private NfcToolCallback callback;

    public void setCallback(NfcToolCallback callback) {
        this.callback = callback;
    }

    private static final String ACTION_NONE = "NONE";
    private static final String ACTION_RESET_DEVICE = "RESET_DEVICE";
    private String action = ACTION_NONE;

    private static final Integer PRODUCT_ID_BLE_DIM = 0x03000001;
    private static final Integer PRODUCT_ID_BLE_CCT = 0x03000002;
    private static final List<Integer> ALL_PRODUCT_ID = Arrays.asList(PRODUCT_ID_BLE_DIM, PRODUCT_ID_BLE_CCT);

    private Handler uiHandler = new Handler(Looper.getMainLooper());

    public static NfcToolManager getInstance() {
        return Singleton.instance;
    }

    private static final String LOG_TAG = "NfcToolManager";

    private NfcToolManager() {

    }

    private static final class Singleton {
        static final NfcToolManager instance = new NfcToolManager();
    }

    public void resetDevice(Tag tag) {

        connectNfcTag(tag, ACTION_RESET_DEVICE);
    }

    private void connectNfcTag(Tag tag, String action) {

        this.action = action;

        NfcA nfca = NfcA.get(tag);

        if (nfca == null) {

            if (callback != null) {
                didNfcFailedHandler();
            }

            return;
        }

        new Thread(new Runnable() {
            @Override
            public void run() {

                try {

                    nfca.connect();

                    // Auth
                    byte[] authBytes = new byte[]{(byte) 0x1B, (byte) 0x33, (byte) 0x38, (byte) 0x33, (byte) 0x39};
                    byte[] authResult = nfca.transceive(authBytes);
                    String authString = HexUtil.getStringByBytes(authResult);
                    Log.i(LOG_TAG, "auth result: " + authString);

                    // Read device type
                    byte[] readConfigBytes = new byte[]{(byte) 0x30, 0x07};
                    byte[] readBytes = nfca.transceive(readConfigBytes);
                    // If device type is in ALL_PRODUCT_ID, then go on.
                    if (readDeviceTypeHandler(readBytes)) {
                        switch (action) {

                            case ACTION_RESET_DEVICE:
                                byte[] resetBytes = new byte[]{(byte) 0xA2, (byte) 69, (byte) 0x55, (byte) 0x01, (byte) 0x01, (byte) 0x01};
                                byte[] resetResult = nfca.transceive(resetBytes);
                                String resetString = HexUtil.getStringByBytes(resetResult);
                                Log.i(LOG_TAG, "Reset result: " + resetString);
                                didNfcSucceededHandler();
                                break;

                            default:
                                break;
                        }
                    } else {
                        gotUnsupportedDeviceHandler();
                    }

                } catch (Exception e) {

                    e.printStackTrace();
                    didNfcFailedHandler();

                } finally {

                    try {
                        nfca.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }

    private void didNfcFailedHandler() {

        if (callback == null) return;

        uiHandler.post(new Runnable() {
            @Override
            public void run() {
                callback.nfcToolManagerDidFailed(NfcToolManager.this);
            }
        });
    }

    private void gotUnsupportedDeviceHandler() {

        if (callback == null) return;

        uiHandler.post(new Runnable() {
            @Override
            public void run() {
                callback.nfcToolManagerGotUnsupportedDevice(NfcToolManager.this);
            }
        });
    }

    private void didNfcSucceededHandler() {

        if (callback == null) return;

        uiHandler.post(new Runnable() {
            @Override
            public void run() {
                callback.nfcToolManagerDidSucceeded(NfcToolManager.this);
            }
        });
    }

    private boolean readDeviceTypeHandler(byte[] bytes) {

        if (bytes != null && bytes.length >= 4) {

            int first = ((int) bytes[0] & 0xFF) << 24;
            int second = ((int) bytes[1] & 0xFF) << 16;
            int third = ((int) bytes[2] & 0xFF) << 8;
            int fourth = (int) bytes[3] & 0xFF;
            Integer productId = first | second | third | fourth;
            return ALL_PRODUCT_ID.contains(productId);
        }
        return false;
    }
}
